/*
给定一个二叉树的根节点 root ，和一个整数 targetSum ，求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始，也不需要在叶子节点结束，但是路径方向必须是向下的（只能从父节点到子节点）。

 

示例 1：



输入：root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出：3
解释：和等于 8 的路径有 3 条，如图所示。
示例 2：

输入：root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出：3
 

提示:

二叉树的节点个数的范围是 [0,1000]
-109 <= Node.val <= 109 
-1000 <= targetSum <= 1000 

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/path-sum-iii
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
*/

#include "../stdc++.h"

/**
 * Definition for a binary tree node.
 */
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
public:
    int pathSum(TreeNode* root, int targetSum) {
        if (root) {
            dfs(root, targetSum - root->val);
        } else {
            return 0;
        }
        if (root->left) {
            pathSum(root->left, targetSum);
        }
        if (root->right) {
            pathSum(root->right, targetSum);
        }
        return res;
    }
    void dfs(TreeNode* node, int targetSum) {
        if (targetSum == 0) {
            ++res;
        }
        if (node->left) {
            dfs(node->left, targetSum - node->left->val);
        }
        if (node->right) {
            dfs(node->right, targetSum - node->right->val);
        }
    }
private:
    int res{0};
};

// 穷举
class Solution {
public:
    int pathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) {
            return 0;
        }
        dfs(root, targetSum);
        pathSum(root->left, targetSum);
        pathSum(root->right, targetSum);
        return res;
    }
private:
    int res{0};
    void dfs(TreeNode* node, int targetSum) {
        if (node == nullptr) {
            return;
        }
        if (targetSum == node->val) {
            ++res;
        }
        dfs(node->left, targetSum - node->val);
        dfs(node->right, targetSum - node->val);
    }
};

// 前缀和
class Solution {
public:
    int pathSum(TreeNode* root, int targetSum) {
        prefix[0] = 1;
        return dfs(root, 0, targetSum);
    }
private:
    unordered_map<int, int> prefix; // 保存的是当前点到node中 前缀和与其对应的个数
    int dfs(TreeNode* node, long long curSum, int targetSum) {
        if (node == nullptr) {
            return 0;
        }
        int res{0};
        curSum += node->val;
        if (prefix.count(curSum - targetSum) != 0) {
            res += prefix[curSum - targetSum];
        }
        prefix[curSum] += 1;
        res += dfs(node->left, curSum, targetSum);
        res += dfs(node->right, curSum, targetSum);
        prefix[curSum] -= 1; // 把当前节点的信息清掉
        return res;
    }
};
